//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2005-2007
//
// Object properties dialog - 'Track points' page.
//

# include "StdAfx.h"
# include "Resource.h"
# include "RgnProperties.h"
# include "Map.h"
# include "ListView.h"
# include "PrintUnits.h"
# include "fast_floor.h"
# include "Settings.h"
# include "Globals.h"

enum {
	lvNumber      = 0,
	lvTime        = 1,
	lvDepth       = 2,
	lvTemperature = 3,
	lvAltitude    = 4,
	lvLegLength   = 5,
	lvLegTime     = 6,
	lvSpeed       = 7,
	lvCourse      = 8,
	lvPosition    = 9,
	lvDOP         = 10,

	lvMax
};

void CTrackPointsPage::_FillPoints (HWND _hList) {
	ListView_DeleteAllItems (_hList);

	bool bEmptyColumn [lvMax];
	int nColumn;
	for (nColumn = 0; nColumn < lvMax; ++ nColumn)
		bEmptyColumn [nColumn] = true;

	if (m_rgn.elements.empty ())
		return;
	const points_t & points = m_rgn.elements [0].points;
	const size_t cPoints = points.size ();
	const trackpoints_t & TrackPoints = m_rgn.elements [0].pExtra->TrackPoints;
	const size_t cExtraPoints = TrackPoints.size ();

	// Get time zone bias + daylight saving time bias.
	TIME_ZONE_INFORMATION tzi;
	if (::GetTimeZoneInformation (& tzi) == TIME_ZONE_ID_DAYLIGHT)
		tzi.Bias += tzi.DaylightBias;

	const float fCosY = cPoints > 0 ? ::cos (c_PI*points [0].y/180) : 1;

	size_t cItem = 0;
	for (size_t cPoint = 0; cPoint < cPoints; ++ cPoint) {
		const point_t & point = points [cPoint];

		InsertItem (_hList, cItem, cPoint, "%d", cPoint + 1);

		// Position.
		char strPosition [64];
		PrintPosition (strPosition, point);
		SetSubItemText (_hList, cItem, lvPosition, "%s", strPosition);
		bEmptyColumn [lvPosition] = false;

		double dLegLength = 0;
		double dCourse = 0;
		if (cPoint + 1 < cPoints) {
			const point_t & point1 = points [cPoint + 1];

			dLegLength =   ::hypot (point1.y - point.y, (point1.x - point.x)*fCosY)*40e6/360;
			dCourse = 90 - ::atan2 (point1.y - point.y, (point1.x - point.x)*fCosY)*180/c_PI;
			if (dCourse < 0)
				dCourse += 360;

			// Leg length.
			char strLegLength [32];
			char strLegLengthUnits [16];
			PrintDistance (strLegLength, strLegLengthUnits, dLegLength);
			SetSubItemText (_hList, cItem, lvLegLength, "%s %s", strLegLength, strLegLengthUnits);
			bEmptyColumn [lvLegLength] = false;

			// Course.
			if (dLegLength != 0) {
				char strCourse [32];
				PrintAzimuth (strCourse, dCourse);
				SetSubItemText (_hList, cItem, lvCourse, "%s", strCourse);
				bEmptyColumn [lvCourse] = false;
			}
		}

		if (cPoint < cExtraPoints) {
			const trackpoint_info_t & ExtraPoint = TrackPoints [cPoint];

			// Time.
			if (ExtraPoint.wFlags & trackpoint_info_t::defTime) {
				// Convert to local time.
				DATE dtLocalTime = ExtraPoint.dtTime - float (tzi.Bias)/(24*60);

				// Check milliseconds (NOTE: ::VariantTimeToSystemTime() does not support this).
				int nMilliseconds = 0;
				if (ExtraPoint.wFlags & trackpoint_info_t::defTimeMilliseconds) {
					const float fSeconds = (dtLocalTime - fast_floor_d (dtLocalTime))*24*60*60;
					nMilliseconds = fast_floor ((fSeconds - fast_floor (fSeconds))*1000 + .5f);
					dtLocalTime -= nMilliseconds/24./60./60./1000;
				}
				SYSTEMTIME st;
				::VariantTimeToSystemTime (dtLocalTime, & st);

				char strDate [32];
				if (! ::GetDateFormat (LOCALE_USER_DEFAULT, DATE_SHORTDATE, & st, NULL, strDate, sizeof (strDate)/sizeof (strDate [0])))
					strDate [0] = '\0';
				char strTime [32];
				if (! ::GetTimeFormat (LOCALE_USER_DEFAULT, 0, & st, NULL, strTime, sizeof (strTime)/sizeof (strTime [0])))
					strTime [0] = '\0';

				if (ExtraPoint.wFlags & trackpoint_info_t::defTimeMilliseconds)
					SetSubItemText (_hList, cItem, lvTime, "%s %s.%02d", strDate, strTime, (nMilliseconds + 5)/10);
				else
					SetSubItemText (_hList, cItem, lvTime, "%s %s", strDate, strTime);
				bEmptyColumn [lvTime] = false;
			}

			// Depth.
			if (ExtraPoint.wFlags & trackpoint_info_t::defDepth) {
				char strDepth [32];
				char strDepthUnits [16];
				PrintDepth (strDepth, strDepthUnits, ExtraPoint.fDepth);

				SetSubItemText (_hList, cItem, lvDepth, "%s %s", strDepth, strDepthUnits);
				bEmptyColumn [lvDepth] = false;
			}

			// Temperature.
			if (ExtraPoint.wFlags & trackpoint_info_t::defTemperature) {
				char strTemperature [32];
				char strTemperatureUnit [16];
				PrintTemperature (strTemperature, strTemperatureUnit, ExtraPoint.fTemperature);

				SetSubItemText (_hList, cItem, lvTemperature, "%s%s", strTemperature, strTemperatureUnit);
				bEmptyColumn [lvTemperature] = false;
			}

			// Altitude.
			if (ExtraPoint.wFlags & trackpoint_info_t::defAltitude) {
				char strAltitude [32];
				char strAltitudeUnit [16];
				PrintElevation (strAltitude, strAltitudeUnit, ExtraPoint.fAltitude, unMeters, false);

				SetSubItemText (_hList, cItem, lvAltitude, "%s %s", strAltitude, strAltitudeUnit);
				bEmptyColumn [lvAltitude] = false;
			}

			double dLegTime = 0;
			if (cPoint + 1 < cExtraPoints) {
				const trackpoint_info_t & ExtraPoint1 = TrackPoints [cPoint + 1];

				// Leg time.
				if (
					(ExtraPoint.wFlags  & trackpoint_info_t::defTime) &&
					(ExtraPoint1.wFlags & trackpoint_info_t::defTime)
				) {
					dLegTime = (ExtraPoint1.dtTime - ExtraPoint.dtTime)*24*60*60;
					const float fLegTime = ::fabs (dLegTime);

					if (ExtraPoint.wFlags & trackpoint_info_t::defTimeMilliseconds) {
						const int nSecond = fast_floor (fLegTime);
						const int nMinute = nSecond/60;
						const int nHour   = nMinute/60;

						SetSubItemText (
							_hList, cItem, lvLegTime,
							"%d:%02d:%02.2f",
							nHour,
							nMinute  - nHour*60,
							fLegTime - nMinute*60
						);
					} else {
						const int nSecond = fast_floor (fLegTime + .5f);
						const int nMinute = nSecond/60;
						const int nHour   = nMinute/60;

						SetSubItemText (
							_hList, cItem, lvLegTime,
							"%d:%02d:%02d",
							nHour,
							nMinute - nHour*60,
							nSecond - nMinute*60
						);
					}
					bEmptyColumn [lvLegTime] = false;
				}
			}

			// Speed.
			float fSpeed = -1;
			if (ExtraPoint.wFlags & trackpoint_info_t::defSpeed)
				fSpeed = ExtraPoint.fSpeed;
			else {
				if (dLegTime > 0)
					fSpeed = 3.6*dLegLength/::fabs (dLegTime);
			}
			if (fSpeed >= 0) {
				char strSpeed [32];
				char strSpeedUnits [16];
				PrintSpeed (strSpeed, strSpeedUnits, fSpeed);

				SetSubItemText (_hList, cItem, lvSpeed, "%s %s", strSpeed, strSpeedUnits);
				bEmptyColumn [lvSpeed] = false;
			}

			// DOP.
			if (ExtraPoint.wFlags & trackpoint_info_t::defDOP) {
				SetSubItemText (_hList, cItem, lvDOP, "%.1f", ExtraPoint.fDOP);
				bEmptyColumn [lvDOP] = false;
			}
		}

		++ cItem;
	}

	// Delete empty columns.
	for (nColumn = lvMax - 1; nColumn > 0; -- nColumn) {
		if (bEmptyColumn [nColumn])
			ListView_DeleteColumn (_hList, nColumn);
	}

	// Set the best width.
	AutoSizeColumns (_hList);

	if (m_cPoint != -1) {
		SetSelection (_hList, m_cPoint);
		EnsureSelectionVisible (_hList);
	}
}

bool CTrackPointsPage::OnInit (HWND _hwndFocus) {
	// Points.
	const HWND hList = GetDlgItem (IDC_POINTS);
	ListView_SetExtendedListViewStyleEx (hList, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);

	AddColumn (hList, lvNumber,      "#",           true);
	AddColumn (hList, lvTime,        "Time");
	AddColumn (hList, lvDepth,       "Depth",       true);
	AddColumn (hList, lvTemperature, "Temperature", true);
	AddColumn (hList, lvAltitude,    "Altitude",    true);
	AddColumn (hList, lvLegLength,   "Leg",         true);
	AddColumn (hList, lvLegTime,     "Leg Time",    true);
	AddColumn (hList, lvSpeed,       "Speed",       true);
	AddColumn (hList, lvCourse,      "Course",      true);
	AddColumn (hList, lvPosition,    "Position");
	AddColumn (hList, lvDOP,         "DOP");

	_FillPoints (hList);

	return true;
}